from time import gmtime, strftime
import time
from threading import Thread
from multiprocessing import Process, Queue
import timeit

from Strategy.config import STATIC
from PlaceOrder.order import newOrder, CancelAllOrder
from Server.Message.send import send_sms
from MarketData.const import CONST
from GUI.output import PATH
import logging


def placeOrder_multithread(order_new):
    response = []
    que = dict()

    threads = []

    for element in order_new:

        if element['platform'] not in que.keys():
            que[element['platform']] = Queue()

        price = '{0:0.7f}'.format(element['price'])
        if element['platform'] == "huobi":
            price = '{0:0.6f}'.format(element['price'])
        if element['base_cur'] == 'USDT':
            price = '{0:0.2f}'.format(element['price'])
        quantity = quantitySize_order(element['commodity_cur'], element['quantity'])
        thread_order = Thread(target=newOrder_thread, 
                              args=(element['platform'], element['commodity_cur'], element['base_cur'], element['type'],
                                    element['order'], quantity, price, que[element['platform']]))

        thread_order.start()
        threads.append(thread_order)

    for element in order_new:
        try:
            response.append(str(que[element['platform']].get(timeout=60)))
        except Exception as e:
            logging.info("{0} {1} : {2}".format('placeOrder_multithread_get_timeout for ', element, e))

    for thread_order in threads:
        try:
            thread_order.join(timeout=60)
        except Exception as e:
            logging.info("{0} : {1}".format('placeOrder_multithread_error ', e))


    return response


class newOrder_thread:
    def __init__(self,
                 platform, commodity_cur, base_cur, side, type, quantity, price,
                 que):
        try:
            start = timeit.default_timer()

            que.put(newOrder(platform, commodity_cur, base_cur, side, type, quantity, price).result)

            stop = timeit.default_timer()
            logging.info('%-10s%-10.2f' % (platform, stop - start))

        except Exception as e:
            # STATIC.time_error[platform] = timeit.default_timer()

            que.put(str(e))
            # logging.info([e, gmtime()])

            # book = open(PATH.ROOTFOLDER + '/error_log.txt','a')
            # book.write(strftime("%Y-%m-%d %H:%M:%S" + str(e) + "\r\n" , gmtime()))
            # book.close()

            # sms error
            # print(send_sms({'altercode': platform + '.' + commodity_cur + base_cur + '.' + quantity}))
            # logging.info(send_sms({'altercode': platform + '.' + commodity_cur + base_cur + '.' + quantity}, "13116634119"))
            logging.info(send_sms({'altercode': '2.' + platform + '.' + commodity_cur + base_cur + '.' + quantity}, "13354655226"))


def create_newOrder(limit_quantity,
                    commodity_cur, base_cur,
                    platf_order,
                    platform,
                    pairquote, account):
    #output: order list
    order_new = list()

    if not platf_order:
        return order_new

    # 交易时，最小下单量，比如每次1000股。
    minsize = CONST.minsize[commodity_cur]
    # 交易时，货币单位，例如股票只能100股 为一个单位
    lotsize = CONST.lotsize[commodity_cur]

    #place only half volume, 90% account to avoid slippage
    # 获得本次交易中可以买的商品数量
    quantity_bid = min(pairquote[platf_order["bid"]].volume_bid, # 出买价最高的平台的商品交易数量
                    pairquote[platf_order["ask"]].volume_ask, # 出卖价最低的平台的商品交易数量
                    account[platf_order["bid"]].balance[commodity_cur] * 0.5, # 出买价最高的平台的，我的账户的商品的数量 ＊ 0.5
                    account[platf_order["ask"]].balance[base_cur] / # 出卖价最低的平台， 我的账户的base_cur的数量
                       pairquote[platf_order["ask"]].price_ask / # 出卖价最低的平台的商品的价格，即多少个base_cur
                       (1+CONST.fee[platf_order["ask"]]) * 0.5, # 上面的公式，即算出在出卖价最低的平台上，我的账户的可以交易的商品数量的一半是多少，同时也把成本算进去了
                    limit_quantity) # 限制交易数量上线
    quantity_bid =  int(quantity_bid / lotsize) * lotsize

    #place order on quantity_ask is different from quantity_bid, as fee is on bought base_cur
    # 获得本次交易中可以卖的商品数量
    quantity_ask = quantity_bid * (1+CONST.fee[platf_order["ask"]])
    quantity_ask = int(quantity_ask / lotsize) * lotsize

    if quantity_bid >= minsize:
        order_new.append({'platform':platf_order["bid"], 'commodity_cur':commodity_cur, 'base_cur':base_cur,  
                    'type':"sell", 'order':"market", 
                    'quantity':quantity_bid, 'price':pairquote[platf_order["bid"]].price_bid})
        order_new.append({'platform':platf_order["ask"], 'commodity_cur':commodity_cur, 'base_cur':base_cur,  
                    'type':"buy", 'order':"market", 
                    'quantity':quantity_ask, 'price':pairquote[platf_order["ask"]].price_ask})

    return order_new


def quantitySize_order(commodity_cur, quantity_org):
    if CONST.lotsize[commodity_cur] < 0.0011:
        quantity = "%.3f" % quantity_org
    elif CONST.lotsize[commodity_cur] < 0.011:
        quantity = "%.2f" % quantity_org
    elif CONST.lotsize[commodity_cur] < 0.11:
        quantity = "%.1f" % quantity_org
    elif CONST.lotsize[commodity_cur] < 1.1:
        quantity = "%.0f" % quantity_org

    return quantity


def cancelAllOrder(platforms):
    response = []
    que = dict()
    threads = []

    for platf in platforms:
        que[platf] = Queue()
        thread_position = Thread(target=cancelOrder_thread, args=(platf, que[platf]))
        thread_position.start()
        threads.append(thread_position)

    time.sleep(0.1)
    for platf in platforms:
        try:
            response.append(str(que[platf].get(timeout=60)))
        except Exception as e:
            logging.info(e)

    for thread_position in threads:
        try:
            thread_position.join(timeout=60)
        except Exception as e:
            logging.info(e)

    return response


class cancelOrder_thread:
    def __init__(self, platform, que):
        try:
            start = timeit.default_timer()

            que.put({platform: CancelAllOrder(platform).result})

            stop = timeit.default_timer()
            logging.info('%-10s%-10.2f' % (platform, stop - start))

        except Exception as e:
            que.put(e)
            # logging.info(e)
            # sms error
            logging.info(send_sms({'altercode': platform + "cancel"},
                                  "13354655226"))
